package org.wattdepot.cli.commands;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.xml.datatype.XMLGregorianCalendar;
import org.wattdepot.client.BadXmlException;
import org.wattdepot.client.MiscClientException;
import org.wattdepot.client.NotAuthorizedException;
import org.wattdepot.client.ResourceNotFoundException;
import org.wattdepot.client.WattDepotClient;
import org.wattdepot.util.tstamp.Tstamp;

/**
 * This class contains a command that prints out the maximum, minimum, or average power generated by
 * the source for the day.
 * 
 * Modified by David Mau.
 * @author Nathaniel Ashe
 * 
 */
public class PowerSamplingCommand implements WattDepotCliCommand {
  // Default client-server connection to use unless given one.
  private WattDepotClient client = new WattDepotClient(debug);
  
  /**
   * This constructor makes sure that the client really is connected to the server.
   * 
   * @param anotherClient Specifies if the user wants to use another WattDepot server
   * other than the default simulation one.
   */
  public PowerSamplingCommand( String anotherClient ) {
    // If another client is provided
    if ( anotherClient != null ) {
      client = new WattDepotClient( anotherClient );
    }
    
    // Stop right away if we cannot contact server.
    if (!client.isHealthy()) {
      System.out.println("Failed to connect to " + client.getWattDepotUri());
      return;
    }
    // Indicate successful connection.
    //System.out.println("Connected to " + client.getWattDepotUri());
  }

  /**
   * This method returns a double that is either the max, min, or average power generated or power
   * consumed by a source given a time stamp.
   * 
   * @param args A list of arguments given to this command.
   * @return A string in MegaWatts of the min, max, or average power consumed or generated for the
   * day.
   */
  public String doCommand(List<String> args) {
    String output = "";
    int interval;
    ArrayList<Double> doubleList = new ArrayList<Double>();
    Double power = 0.0;
    Double totalPower = 0.0;

    if (args.size() > 4) {
      output = "Too many arguments.";
      output = output.concat(cr);
      return output;
    }
    if (args.size() < 4) {
      output = "Missing arguments.";
      output = output.concat(cr);
      return output;
    }
    
    String source = args.get(0);
    String day = args.get(1);
    String minutes = args.get(2);
    String solution = args.get(3);

    try {
      interval = Integer.valueOf(minutes);
    }
    catch (NumberFormatException e) {
      output = intervalNotNumber;
      output = output.concat(e.toString());
      output = output.concat(cr);
      return output;
    }

    // If the converted integer is negative or zero, return an error.
    if (interval <= 0) {
      output = intervalNegativeOrZero;
      output = output.concat(cr);
      return output;
    }

    XMLGregorianCalendar xmlTimeStart = null;
    try {
      xmlTimeStart = Tstamp.makeTimestamp(day);
    }
    catch (Exception e) {
      output = badTimeStamp;
      output = output.concat(e.toString());
      output = output.concat(cr);
      return output;
    }
    XMLGregorianCalendar xmlTimeEnd = null;
    try {
      xmlTimeEnd = Tstamp.makeTimestamp(day);
      xmlTimeEnd = Tstamp.incrementDays(xmlTimeEnd, 1);
    }
    catch (Exception e) {
      output = badTimeStamp;
      output = output.concat(e.toString());
      output = output.concat(cr);
      return output;
    }

    while (xmlTimeStart.getDay() < xmlTimeEnd.getDay()) {
      try {
        power = client.getPowerGenerated(source, xmlTimeStart) / 1000000;
      }
      catch (NotAuthorizedException e) {
        output = notAuthorized;
        output = output.concat(e.toString());
        output = output.concat(cr);
        return output;
      }
      catch (ResourceNotFoundException e) {
        output = resourceNotFound;
        output = output.concat(e.toString());
        output = output.concat(cr);
        return output;
      }
      catch (BadXmlException e) {
        output = badXml;
        output = output.concat(e.toString());
        output = output.concat(cr);
        return output;
      }
      catch (MiscClientException e) {
        output = miscClient;
        output = output.concat(e.toString());
        output = output.concat(cr);
        return output;
      }

      totalPower += power;
      doubleList.add(power);
      xmlTimeStart = Tstamp.incrementMinutes(xmlTimeStart, interval);
    }

    Collections.sort(doubleList);
    if ("max".equals(solution)) {
      output += Collections.max(doubleList) + " Megawatts";
    }
    else if ("min".equals(solution)) {
      output += Collections.min(doubleList) + " Megawatts";
    }
    else if ("average".equals(solution)) {
      output += totalPower / doubleList.size() + " Megawatts";
    }
    else {
      output = minOrMaxOrAverage;
      output += cr;
    }

    output += cr;
    return output;
  }
}
